﻿using System;
using System.ComponentModel.Composition;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Input;

namespace ZOIL.Library.Behaviors
{
    [Export(typeof(PluginConnectionBehavior))]
    public class TouchConnectionBehavior : PluginConnectionBehavior
    {
        #region private fields

        private IDisposable _touchConnectionSubscription;

        #endregion

        #region private methods

        private IDisposable RegisterTouchEvents()
        {
            var touchMove = Observable.FromEventPattern<TouchEventArgs>(AssociatedObject, UIElement.TouchMoveEvent.Name);

            var touchDown = Observable.FromEventPattern<TouchEventArgs>(AssociatedObject, UIElement.TouchDownEvent.Name);

            var touchUp = Observable.FromEventPattern<TouchEventArgs>(AssociatedObject, UIElement.TouchUpEvent.Name);

            var touchMoves = from tm in touchMove
                             select tm.EventArgs.GetTouchPoint(null).Position;

            var touchDrag = from tlbd in touchDown.Select(evt =>
            {
                evt.EventArgs.Handled = true;
                return new ConnectionHelper(evt.EventArgs.TouchDevice, new Connection(evt.EventArgs.GetTouchPoint(null).Position));
            }).Do(ch =>
            {
                StartConnection(ch.Connection);
                AssociatedObject.CaptureTouch(ch.TouchDevice);
            })
                            from md in touchMoves.Do(point => tlbd.Connection.EndPoint = point)
                            .TakeUntil(touchUp.Do(evt => tlbd.Connection.EndPoint = evt.EventArgs.GetTouchPoint(null).Position)
                            .Do(evt =>
                            {
                                evt.EventArgs.Handled = true;
                                FinishConnection(tlbd.Connection);
                                AssociatedObject.ReleaseTouchCapture(evt.EventArgs.TouchDevice);
                            }))
                            select tlbd;

            return touchDrag.Select(ch => ch.Connection).Subscribe(ChangeConnection);
        }

        #endregion

        #region overrides

        protected override void OnIsEnabledChanged(bool oldIsEnabled, bool newIsEnabled)
        {
            if (newIsEnabled)
            {
                _touchConnectionSubscription = RegisterTouchEvents();
            }
            else
            {
                if (_touchConnectionSubscription != null)
                    _touchConnectionSubscription.Dispose();
            }
        }

        #endregion

        #region helper class

        private class ConnectionHelper
        {
            public TouchDevice TouchDevice { get; private set; }
            public Connection Connection { get; private set; }

            public ConnectionHelper(TouchDevice touchDevice, Connection connection)
            {
                TouchDevice = touchDevice;
                Connection = connection;
            }
        }

        #endregion
    }
}
